use rand;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Barrier, Condvar, Mutex, RwLock};
use std::thread;

fn main() {
    // 所有线程投掷的总次数
    let total_flips = Arc::new(Mutex::new(0));
    // 执行完成的线程统计
    let completed = Arc::new(Mutex::new(0));

    // 子线程数
    let runs = 8;
    // 要投掷的轮数
    let target_flips = 10;

    // 创建8个子线程抛硬币
    for _ in 0..runs {
        let total_clone = total_flips.clone();
        let completed = completed.clone();
        thread::spawn(move || {
            flip_simulate(target_flips, total_clone);
            let mut completed = completed.lock().unwrap();
            *completed += 1;
        });
    }

    // ------------   无死锁版本 -----------
    // 等待所有子线程完成投掷
    loop {
        let completed = completed.lock().unwrap();
        if *completed == runs {
            // 打印平均数
            let total_count = total_flips.lock().unwrap();
            println!("final average:{}", *total_count / runs);
            break;
        }
    }

    // -------  死锁版本 ： 没有break语句，主线程会一直持有 mutex的锁，导致子线程无法获取锁去执行， 而主线程又一直在等待子线程的执行结果,所以死锁； -----
    // let completed = completed.lock().unwrap();
    // while *completed < runs {
    //     let total_count = total_flips.lock().unwrap();
    //     println!("final average:{}", *total_count / runs);
    // }

    // 执行读写锁
    rw_lock();

    // 执行内存屏障的测试
    barrier();

    // 执行条件变量
    condivar();

    // 执行自旋锁
    spin_lock();
}

// 模拟投掷硬币，连续投掷10次正面为一轮。 target_flips 要达到的正面朝上的目标数，total_flips 所有线程统计的投掷硬币总数
fn flip_simulate(target_flips: u64, total_flips: Arc<Mutex<u64>>) {
    // 连续投掷出正面的次数
    let mut continue_positive = 0;
    // 投掷硬币的总次数
    let mut iter_count = 0;

    while continue_positive <= target_flips {
        iter_count += 1;
        let pro_or_on: bool = rand::random();
        if pro_or_on {
            continue_positive += 1;
        } else {
            continue_positive = 0;
        }
    }

    println!("iter_counts:{}", iter_count);
    let mut total_flips = total_flips.lock().unwrap();
    *total_flips += iter_count;
}

// 读写锁的测试
fn rw_lock() {
    let rw_lock = RwLock::new(5);
    // 通过read获取读锁
    {
        let r1 = rw_lock.read().unwrap();
        let r2 = rw_lock.read().unwrap();
        assert_eq!(*r1, 5);
        assert_eq!(*r2, 5);
    }

    // 通过write获取写锁，读写锁不能同时存在，需要分隔开
    {
        let mut w = rw_lock.write().unwrap();
        *w += 1;
        assert_eq!(*w, 6);
    }
}

// 屏障,通过wait方法在某个点阻塞全部进入临界区的线程
fn barrier() {
    let mut v = Vec::with_capacity(5);
    let barrier = Arc::new(Barrier::new(5));
    for _ in 0..5 {
        let c = barrier.clone();
        v.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }

    for h in v {
        h.join().unwrap();
    }
}

// 条件变量 ，与屏障类似，但是不阻塞全部线程，而是在满足指定条件之前阻塞某一个得到互斥锁的线程
fn condivar() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair_c = pair.clone();

    thread::spawn(move || {
        let &(ref lock, ref cvar) = &*pair_c;
        let mut started = lock.lock().unwrap();
        *started = true;
        cvar.notify_one();
    });

    let &(ref lock, ref cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        println!("{}", *started); // false
                                  // 主线程在此处等待子线程的通知，
        started = cvar.wait(started).unwrap();
        println!("{}", *started); // true
    }
}

// 使用原子类型实现自旋锁
fn spin_lock() {
    let spinlock = Arc::new(AtomicUsize::new(1));
    let spinlock_c = spinlock.clone();
    let thread = thread::spawn(move || {
        // Ordering::SeqCst 是内存顺序，排序一致性
        spinlock_c.store(0, Ordering::SeqCst);
    });

    while spinlock.load(Ordering::SeqCst) != 0 {}
    if let Err(panic) = thread.join() {
        println!("thread had an error {:?}", panic);
    };
}
